#include "MessageQueue.h"

using namespace std;
std::map<std::string, MessageQueue*> MessageQueueList;
MessageQueue::MessageQueue(const std::string& name) : mq_name(name), mq(-1) {
    MessageQueueList[name] = this;


    mq_attr = {0}; 
    mq_attr.mq_maxmsg = 10;  
    mq_attr.mq_msgsize = 256; 

    mq = mq_open(mq_name.c_str(), O_CREAT | O_EXCL | O_RDWR, 0644, &mq_attr);
    if (mq == (mqd_t) -1) {
        throw std::runtime_error("Failed to create message queue: " + std::string(strerror(errno)));
    }
}

MessageQueue::MessageQueue(const std::string& name, bool open_existing) : mq_name(name), mq(-1) {
    // 将当前对象添加到全局的消息队列列表中
    MessageQueueList[name] = this;
    mq_attr = {0}; 
    mq_attr.mq_maxmsg = 10;  
    mq_attr.mq_msgsize = 256; 


    if (open_existing) {
        // 尝试以只读模式打开消息队列
        mq = mq_open(mq_name.c_str(), O_RDONLY);
        if (mq == (mqd_t)-1) {  // 这里应该是 mq，而不是 mqd
            if (errno == ENOENT) {
                // 消息队列不存在
                std::cerr << "Message queue does not exist: " << strerror(errno) << std::endl;
            } else {
                // 其他错误
                std::cerr << "Failed to open message queue: " << strerror(errno)<< std::endl;
            }
        } else {
            // 消息队列存在，关闭只读模式的文件描述符
            mq_close(mq);
            // 将文件描述符重置为 -1，以便后续操作能正确处理
            mq = -1;
        }
    }

    cout<<"准备创建 mq:"<<mq_name.c_str()<<endl;
    // 创建或打开消息队列时设置了 mq 标志，确保使用了正确的文件描述符
    if (mq == -1) {
        // 如果未成功打开或创建消息队列，则创建一个新的消息队列
        mq = mq_open(mq_name.c_str(), O_RDWR | O_CREAT, 0644, &mq_attr);
        if (mq == (mqd_t)-1) {
            throw std::runtime_error("队列创建失败: " + std::string(strerror(errno)));
            exit -1;
        }
    }

    // 获取消息队列的属性
    if (mq_getattr(mq, &mq_attr) == -1) {
        throw std::runtime_error("Failed to get message queue attributes: " + std::string(strerror(errno)));
    }

    std::cout << "Number of messages currently in the queue: " << mq_attr.mq_curmsgs << std::endl;
    if( mq_attr.mq_curmsgs > 0 )
        cleanMessage();

}

MessageQueue::~MessageQueue()
{
    if (mq != -1) {
        if (mq_close(mq) == -1) {
            std::cerr << "Error closing message queue: " << strerror(errno) << std::endl;
        }
        mq = -1;
    }

    if (!mq_name.empty() && mq_name[0] == '/') {
        if (mq_unlink(mq_name.c_str()) == -1) {
            std::cerr << "Error unlinking message queue: " << strerror(errno) << std::endl;
        }
    }
}
void MessageQueue::cleanMessage()
{
    char* buffer = new char[mq_attr.mq_msgsize];
    ssize_t bytesRead;
    while ((bytesRead = mq_receive(mq, buffer, mq_attr.mq_msgsize, NULL)) != -1)
    {
    // If we reach here, it means a message was read and discarded
        std::cout << "Discarded message of size: " << bytesRead << " bytes" << std::endl;
    }
    if (errno != EAGAIN) 
    {
    std::cerr << "Error reading from message queue: " << strerror(errno) << std::endl;
    }
    delete[] buffer;
}



void MessageQueue::sendMessage(const std::string& message) {
    std::lock_guard<std::mutex> lock(mutex);
    if (mq == -1) {
        throw std::runtime_error("Message queue not open.");
    }
    if (mq_send(mq, message.c_str(), message.size() + 1, 0) == -1) {
        throw std::runtime_error("Failed to send message: " + std::string(strerror(errno)));
    }
}

std::string MessageQueue::receiveMessage() {
    std::lock_guard<std::mutex> lock(mutex);
    if (mq == -1) {
        throw std::runtime_error("Message queue not open.");
    }

    struct mq_attr attr;
    if (mq_getattr(mq, &attr) == 0) 
    {
        if (attr.mq_curmsgs > 0) {
            // 队列中有消息
        } else {
            return std::string("", 0);
        }
    }

    char buffer[mq_attr.mq_msgsize];
    ssize_t bytes_read = mq_receive(mq, buffer, mq_attr.mq_msgsize, nullptr);
    if (bytes_read == -1) {
        throw std::runtime_error("Failed to receive message: " + std::string(strerror(errno)));
    }
    return std::string(buffer, bytes_read);
}

void MessageQueue::printAttributes() {
    std::lock_guard<std::mutex> lock(mutex);
    if (mq == -1) {
        std::cerr << "Message queue not open." << std::endl;
        return;
    }
    std::cout << "Message queue attributes:" << std::endl;
    std::cout << "  Maximum number of messages: " << mq_attr.mq_maxmsg << std::endl;
    std::cout << "  Maximum message size: " << mq_attr.mq_msgsize << " bytes" << std::endl;
    std::cout << "  Current number of messages: " << mq_attr.mq_curmsgs << std::endl;
}
